feat(core): GSAP keyframe parsing, mutations, and API routes [1/6]#1167
Conversation
Fallow audit reportFound 46 findings. Duplication (33)
Health (13)
Generated by fallow. |
c1cc15d to
0dae94d
Compare
0dae94d to
20f6ede
Compare
20f6ede to
99f09cf
Compare
jrusso1020
left a comment
There was a problem hiding this comment.
Foundational PR for the stack. The parser shape is the right altitude — three GSAP keyframe formats (percentage / object-array / simple-array) cleanly distinguished by AST inspection, mutations operate via AST round-trip (not string rewrite), and the auto-collapse-to-flat-tween behavior on <2 keyframes is a nice ergonomic. 92 test cases cover the important shapes.
Strengths confirmed:
CSS_IDENTITYmap (opacity:1, scale:1, autoAlpha:1) for synthesizing implicit-from values when convertingto()→ keyframes is the right approach. Falling back to0for everything else is documented and reasonable.removeKeyframeFromScriptauto-collapses to flat tween when < 2 keyframes remain, preserving the last keyframe's properties. Good DX.DROPPED_VAR_KEYScorrectly removeskeyframesfrom the drop set (now parsed) while keepingonComplete/onStart/etc. dropped. Callbacks remain out of scope.
Non-blocking nits:
-
Object-array percentage collisions on small durations —
parseObjectArrayKeyframescomputes positions viaMath.round((cumulative / totalDuration) * 100). Two adjacent keyframes with very small durations (e.g., 0.01s + 0.01s out of a 5s timeline) round to the same percentage. The mutation functions key on percentage exact-match (existingIdx !== -1) and silently replace. If a round-trip parse loses a keyframe, the next mutation can't address it. Worth either: (a) using higher-precision percentages internally (decimals), or (b) documenting the loss in the parse function's doc. -
Mutation functions only operate on percentage-format —
findKeyframesObjectNodematchesObjectExpressiononly. If a tween was parsed from object-array or simple-array format,addKeyframeToScript/updateKeyframeInScript/ etc. silently return the input unchanged. Either: (a) document that mutations require percentage format, or (b) add a "normalize to percentage" pre-step that rewrites object-array/simple-array tweens before mutating. Caller can't currently introspect which format a tween uses. -
resolvedFromValuesparam name inconvertToKeyframesInScript— forfrom()tweens, this is actually the to-state (the resolved current DOM state, sincefrom()means "start FROM these values and animate TO current DOM"). The current name suggests "from values" universally. SuggestoppositeStateValuesor a docstring example. The semantics are correct — just the naming is misleading. -
API route — no percentage range validation — the new
add-keyframe/update-keyframecases accept arbitrarypercentage: number. Negative or > 100 values get serialized as e.g."-50%"which the parser would happily round-trip but GSAP behavior is undefined. One-line guard:if (body.percentage < 0 || body.percentage > 100) return c.json({error: "percentage out of range"}, 400). -
Three
fallow-ignore-next-line complexitydirectives in the new parse functions. Acceptable for irreducible parser branching across three formats; just flagging that they're load-bearing. -
Missing test cases — no test for: (a) mutations on object-array/simple-array format tweens (current behavior is silent no-op), (b) negative or >100 percentages, (c) tween with
extrasthat survive aconvertToKeyframesInScriptround-trip.
Architecture solid. James gates stamps on my end. From a correctness perspective the parser + mutation primitives are ready.
Review by Jerrai (hyperframes specialist)

Summary
Parse native GSAP keyframes in 3 formats (percentage, object-array, simple-array). 5 mutation functions (add/remove/update keyframe, convert-to-keyframes, remove-all). Expand SUPPORTED_PROPS to 21. Studio API routes for all mutation types. 92 test cases.
Part 1 of 6 — core parser foundation. No UI changes.
Test plan
bun run --cwd packages/core test— all parser tests pass